package com.jfs.security.spj;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.jfs.entity.OperationLog;
import com.jfs.security.annotations.Log;
import com.jfs.security.properties.SecurityProperties;
import com.jfs.security.service.OperationLogService;
import com.jfs.security.utils.HttpServletUtils;
import com.jfs.security.utils.IpUtils;
import com.jfs.security.utils.JwtTokenUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @Description 日志注解切面
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022/8/8
 */
@Aspect
@Component
@Order(1)
@Slf4j
@AllArgsConstructor
public class LogAspect {
    private final SecurityProperties securityProperties;
    private final OperationLogService operationLogService;

    /**
     * 日志切面
     *
     * @param proceedingJoinPoint
     * @param log
     */
    @Around("@annotation(log)")
    public Object process(ProceedingJoinPoint proceedingJoinPoint, Log log) throws Throwable {
        OperationLog operationLog = new OperationLog();
        //获取请求ip地址
        String ip = IpUtils.getIpAddr(HttpServletUtils.getHttpServletRequest());
        operationLog.setRequestIp(ip);
        //获取请求地址
        String requestURI = HttpServletUtils.getHttpServletRequest().getRequestURI();
        operationLog.setRequestUrl(requestURI);
        //设置请求方法
        String requestMethod = HttpServletUtils.getHttpServletRequest().getMethod();
        operationLog.setRequestMethod(requestMethod);
        // 设置方法名称
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        String methodName = proceedingJoinPoint.getSignature().getName();
        String method = className + "." + methodName + "()";
        operationLog.setMethod(method);
        //获取当前登录用户名
        String tokenForRequest = JwtTokenUtils.getTokenForRequest();
        //如果用户取出为空则为匿名用户
        String userName = "anonymous";
        if (Objects.nonNull(tokenForRequest) && !JwtTokenUtils.isTokenExpired(tokenForRequest, securityProperties.getSecret())) {
            String usernameFromToken = JwtTokenUtils.getUsernameFromToken(tokenForRequest, securityProperties.getSecret());
            if (StrUtil.isNotEmpty(usernameFromToken)) {
                userName = usernameFromToken;
            }
        }
        operationLog.setUserName(userName);
        //设置操作名称
        String name = log.name();
        operationLog.setTitle(name);
        //设置请求参数
        Object[] args = proceedingJoinPoint.getArgs();
        operationLog.setRequestParam(JSONUtil.toJsonStr(args));
        //获取请求时间
        DateTime executeTime = DateUtil.date();
        operationLog.setExecuteTime(executeTime);
        //执行程序
        boolean sign = true;
        Throwable throwable = null;
        Object result = null;
        try {
            //执行方法
            result = proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            sign = false;
            throwable = e;
        }
        DateTime endTime = DateUtil.date();
        //设置响应时间
        Long responseTime = endTime.getTime() - executeTime.getTime();
        operationLog.setResponseTime(responseTime);
        //设置执行是否正常
        if (sign) {
            operationLog.setStatus(1);
        } else {
            operationLog.setStatus(0);
            operationLog.setErrorMsg(throwable.getMessage());
        }
        //设置响应结果参数
        if (Objects.nonNull(result)) {
            operationLog.setRequestResult(JSONUtil.toJsonStr(result));
        }
        operationLogService.saveOperationLog(operationLog);
        if (Objects.isNull(throwable)){
            return result;
        }else {
            throw throwable;
        }
    }
}
